import%20marimo%0A%0A__generated_with%20%3D%20%220.18.4%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Goal%0A%0A%20%20%20%20Show%20all%20London%20subway%20stations%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20%23%20Imports%20and%20generic%20utility%20methods%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20duckdb%0A%20%20%20%20import%20geopandas%20as%20gpd%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20from%20shapely%20import%20wkt%0A%20%20%20%20return%20duckdb%2C%20gpd%2C%20pd%2C%20wkt%0A%0A%0A%40app.cell%0Adef%20_(duckdb)%3A%0A%20%20%20%20def%20duckdb_connection()%3A%0A%20%20%20%20%20%20%20%20conn%20%3D%20duckdb.connect()%0A%20%20%20%20%20%20%20%20conn.install_extension('spatial')%0A%20%20%20%20%20%20%20%20conn.load_extension('spatial')%0A%20%20%20%20%20%20%20%20return%20conn%0A%20%20%20%20return%20(duckdb_connection%2C)%0A%0A%0A%40app.cell%0Adef%20_(gpd%2C%20wkt)%3A%0A%20%20%20%20def%20load_area(conn%2C%20overture_local_base%2C%20overture_theme%2C%20overture_type%2C%20bbox)%3A%0A%20%20%20%20%20%20%20%20(minx%2Cminy%2Cmaxx%2Cmaxy)%20%3D%20bbox%0A%20%20%20%20%20%20%20%20path%20%3D%20f%22%7Boverture_local_base%7D%2Ftheme%3D%7Boverture_theme%7D%2Ftype%3D%7Boverture_type%7D%2F*%22%0A%20%20%20%20%20%20%20%20query%20%3D%20f%22%22%22%0A%20%20%20%20%20%20%20%20SELECT%20*%20EXCLUDE(geometry)%2C%20ST_AsText(geometry)%20AS%20geometry%20%0A%20%20%20%20%20%20%20%20FROM%20read_parquet('%7Bpath%7D')%0A%20%20%20%20%20%20%20%20WHERE%20bbox.xmin%20%3E%3D%20%7Bminx%7D%0A%20%20%20%20%20%20%20%20%20%20AND%20bbox.xmax%20%3C%3D%20%7Bmaxx%7D%0A%20%20%20%20%20%20%20%20%20%20AND%20bbox.ymin%20%3E%3D%20%7Bminy%7D%0A%20%20%20%20%20%20%20%20%20%20AND%20bbox.ymax%20%3C%3D%20%7Bmaxy%7D%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20arrow_table%20%3D%20conn.execute(query).fetch_arrow_table()%0A%20%20%20%20%20%20%20%20df%20%3D%20arrow_table.to_pandas()%0A%20%20%20%20%20%20%20%20gdf%20%3D%20gpd.GeoDataFrame(%0A%20%20%20%20%20%20%20%20%20%20%20%20df%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20geometry%3Ddf%5B'geometry'%5D.apply(wkt.loads)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20crs%3D%22EPSG%3A4326%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20return%20gdf%0A%20%20%20%20return%20(load_area%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Load%20London%20area%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20%23%20London%20bbox%20based%20on%20example%20on%20https%3A%2F%2Fwiki.openstreetmap.org%2Fwiki%2FBounding_box%0A%20%20%20%20%23%20We%20could%20derive%20this%20based%20on%20the%20GERS%20id%2C%20but%20not%20for%20now%0A%20%20%20%20london_bbox%20%3D%20(-0.489%2C51.28%2C0.236%2C51.686)%0A%20%20%20%20return%20(london_bbox%2C)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20overturemaps_release%20%3D%20%222025-12-17.0%22%0A%20%20%20%20overturemaps_base%20%3D%20f%22%2FVolumes%2FPRO-G40%2FOvertureMaps%2Fdata%2Frelease%2F%7Boverturemaps_release%7D%22%0A%20%20%20%20return%20(overturemaps_base%2C)%0A%0A%0A%40app.cell%0Adef%20_(duckdb_connection)%3A%0A%20%20%20%20conn%20%3D%20duckdb_connection()%0A%20%20%20%20return%20(conn%2C)%0A%0A%0A%40app.cell%0Adef%20_(conn%2C%20load_area%2C%20london_bbox%2C%20overturemaps_base)%3A%0A%20%20%20%20london_segments_gdf%20%3D%20load_area(conn%2C%20overturemaps_base%2C%20%22transportation%22%2C%20%22segment%22%2C%20london_bbox)%0A%20%20%20%20return%20(london_segments_gdf%2C)%0A%0A%0A%40app.cell%0Adef%20_(london_segments_gdf)%3A%0A%20%20%20%20london_segments_gdf.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Find%20subway%20connectors%0A%0A%20%20%20%20Find%20the%20connectors%20that%20are%20attached%20to%20segments%20that%20are%20labelled%20as%20subways%2C%20implying%20these%20connectors%20are%20in%20the%20subway%20(tube).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(pd)%3A%0A%20%20%20%20def%20find_subway_segment_with_connectors(gdf)%3A%0A%20%20%20%20%20%20%20%20%23%20restrict%20to%20only%20those%20segments%20that%20belong%20to%20a%20subway%0A%20%20%20%20%20%20%20%20subway_segment_gdf%20%3D%20gdf%5Bgdf%5B%22class%22%5D%20%3D%3D%20'subway'%5D%0A%0A%20%20%20%20%20%20%20%20%23%20each%20segment%20has%20a%20list%20of%20connectors%20(stops%20along%20it)%0A%20%20%20%20%20%20%20%20%23%20create%20a%20dataframe%20which%20contains%20one%20row%20for%20each%0A%20%20%20%20%20%20%20%20%23%20connector%2C%20along%20with%20all%20segment%20information%0A%20%20%20%20%20%20%20%20exploded_gdf%20%3D%20subway_segment_gdf.explode(%22connectors%22)%0A%0A%20%20%20%20%20%20%20%20%23%20create%20a%20new%20dataframe%20which%20contains%20a%20new%0A%20%20%20%20%20%20%20%20%23%20%60connector_id%60%20column%2C%20but%20is%20indexed%20by%20the%20original%0A%20%20%20%20%20%20%20%20%23%20%60exploded_gdf%60%20dataframe%0A%20%20%20%20%20%20%20%20connectors_df%20%3D%20pd.DataFrame(exploded_gdf%5B%22connectors%22%5D.tolist()%2C%20index%3Dexploded_gdf.index)%0A%0A%20%20%20%20%20%20%20%20%23%20join%20it%20back%20to%20exploded%20df%20so%20we%20end%20up%20with%20a%20new%20%0A%20%20%20%20%20%20%20%20%23%20%60connector_id%60%20on%20each%20repeated%20segment%0A%20%20%20%20%20%20%20%20joined_gdf%20%3D%20exploded_gdf.join(connectors_df)%0A%0A%20%20%20%20%20%20%20%20return%20joined_gdf%0A%20%20%20%20return%20(find_subway_segment_with_connectors%2C)%0A%0A%0A%40app.cell%0Adef%20_(find_subway_segment_with_connectors%2C%20london_segments_gdf)%3A%0A%20%20%20%20london_subway_segment_gdf%20%3D%20find_subway_segment_with_connectors(london_segments_gdf)%0A%20%20%20%20london_subway_segment_gdf.head()%0A%20%20%20%20return%20(london_subway_segment_gdf%2C)%0A%0A%0A%40app.cell%0Adef%20_(conn%2C%20load_area%2C%20london_bbox%2C%20overturemaps_base)%3A%0A%20%20%20%20london_connectors_gdf%20%3D%20load_area(conn%2C%20overturemaps_base%2C%20%22transportation%22%2C%20%22connector%22%2C%20london_bbox)%0A%20%20%20%20london_connectors_gdf.head()%0A%20%20%20%20return%20(london_connectors_gdf%2C)%0A%0A%0A%40app.function%0Adef%20restrict_to_connectors(connector_gdf%2C%20subset_gdf)%3A%0A%20%20%20%20subsetted_gdf%20%3D%20(%0A%20%20%20%20%20%20%20%20connector_gdf.merge(subset_gdf.loc%5B%3A%2C%22connector_id%22%5D%2C%0A%20%20%20%20%20%20%20%20left_on%3D%22id%22%2C%0A%20%20%20%20%20%20%20%20right_on%3D%22connector_id%22%2C%0A%20%20%20%20%20%20%20%20how%3D%22inner%22%0A%20%20%20%20))%0A%20%20%20%20return%20subsetted_gdf.drop_duplicates(subset%3D'id')%0A%0A%0A%40app.cell%0Adef%20_(london_connectors_gdf%2C%20london_subway_segment_gdf)%3A%0A%20%20%20%20london_connectors_restricted_gdf%20%3D%20restrict_to_connectors(london_connectors_gdf%2C%20london_subway_segment_gdf)%0A%20%20%20%20london_connectors_restricted_gdf.head()%0A%20%20%20%20return%20(london_connectors_restricted_gdf%2C)%0A%0A%0A%40app.cell%0Adef%20_(london_connectors_restricted_gdf)%3A%0A%20%20%20%20london_connectors_restricted_gdf.explore()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(london_connectors_restricted_gdf)%3A%0A%20%20%20%20london_connectors_restricted_gdf.explore(tiles%3D%22CartoDB%20positron%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
2a3a7cafa85565e83131d0c44c4aa411